#include "steamapibackend.h"
#include "sdk/public/steam/steam_api.h"
#include "avatarimageprovider.h"
#include <QNetworkAccessManager>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include <QQuickWindow>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QProcess>
#include "friendmodel.h"
#include "lobbymodel.h"
#include "gamehistorymodel.h"

bool G_Steam_Backend_Initialized = false;
extern QQmlApplicationEngine *engine;
const char * SERVER_IP = "94.74.123.22";
inline void setStatusBarText(const char *text) {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("status_bar_label");
    item->setProperty("text", text);
}

inline void setStartGameProgressText(const char *text) {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("wait_time_label");
    item->setProperty("text", text);
}

inline void enableStartQueueButton() {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("start_match_button");
    item->setProperty("enabled", true);
}

inline void enableTestLaunchButton() {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("test_launch_button");
    item->setProperty("enabled", true);
    item = window->findChild<QQuickItem *>("init_failed_label");
    item->setProperty("visible", true);
}

inline void setPlayerScore(int score, int win, int loss) {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("player_score_label");
    item->setProperty("text", QString("%1").arg(score));
    int total = win + loss;
    QString win_rate = "0%";
    if (total > 0) {
        win_rate = QString("%1").arg(win * 100 / total) + "%";
    }
    window->findChild<QQuickItem *>("total_games_label")->setProperty("text", QString("%1").arg(total));
    window->findChild<QQuickItem *>("win_percent_label")->setProperty("text", win_rate);
    window->findChild<QQuickItem *>("win_total_label")->setProperty("text", QString("%1").arg(win));
}

inline void setQueueCount(int queue_count) {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("queue_count_label");
    item->setProperty("text", QString("排位人数：%1").arg(queue_count));
}

inline void disableQueueCancelButton() {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QMetaObject::invokeMethod(window, "handleMatchGameFound");
}

inline void setGameJoinStateText(const char *text) {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("game_join_state_label_content");
    item->setProperty("text", text);
}

inline void showReadyButton(bool readyVisible) {
    qDebug() << "showReadyButton " << readyVisible;
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("ready_button");
    item->setProperty("visible", readyVisible);
    item = window->findChild<QQuickItem *>("start_match_button");
    item->setProperty("visible", !readyVisible);
}

inline void disableQueueButton(bool readyVisible) {
    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
    QQuickItem * item = window->findChild<QQuickItem *>("start_match_button");
    item->setProperty("enabled", readyVisible);
}

inline void handleStartQueueResponse(QNetworkReply *reply, int *queueState, long *lastCheckQueueTime) {
    QByteArray qba = reply->readAll();
    if (QString(qba) == "OK") {
        setStatusBarText("Start match making.");
        *queueState = 1;
        *lastCheckQueueTime = QDateTime::currentSecsSinceEpoch() + 5;
    } else {
        qDebug() << QString(qba);
        setStatusBarText("Failed to start match-making.");
    }
}

inline void handleLaunchSuccess(QNetworkReply *reply, QString *gid, int *is_host, SteamAPIBackend *backend) {
    QByteArray qba = reply->readAll();
    qDebug() << "handleLaunchSuccess " << QString(qba);
    QJsonDocument document = QJsonDocument::fromJson(qba);
    if (document.isNull()) {
        qDebug() << "Invalid document";
        setStatusBarText("Failed to get game id.");
        return;
    }
    QJsonObject object = document.object();
    *is_host = object["hst"].toInt();
    *gid = object["gid"].toString();
    if (*is_host == 1) {
        qDebug() << "is host, starting game lobby with id " << *gid;
        backend->launchGameProcess  = new QProcess(backend);
        QStringList qsl = QStringList();
        qsl.append("start");
        qsl.append(*gid);
        backend->launchGameProcess->start("ahks/launch_dota2.exe", qsl);
        backend->launchGameProcess->waitForStarted();
        backend->queueState = 4;
    } else {
        qDebug() << "not host, waiting for host to create game " << *gid;
        setStatusBarText("Game started, wait for host.");
        backend->queueState = 3;
        backend->lastCheckGameHostedTime = QDateTime::currentSecsSinceEpoch();
    }
}

inline void handleQueueStateResponse(QNetworkReply *reply, int *queueState, SteamAPIBackend *backend) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    QByteArray qba = reply->readAll();
    qDebug() << "handleQueueStateResponse " << status_code;
    if (status_code == 200) {
        qDebug() << "Matchmaking game found";
        *queueState = 2;
        setStatusBarText("Matchmaking game found, starting game");
        backend->launchGameProcess = new QProcess(backend);
        QStringList qsl = QStringList();
        qsl.append("dota2");
        backend->launchGameProcess->start("ahks/launch_dota2.exe", qsl);
        backend->launchGameProcess->waitForStarted();
        disableQueueCancelButton();
    }
}

inline void handleGameState(QNetworkReply *reply, SteamAPIBackend *backend) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "handleGameState" << status_code;
    if (status_code == 200) {
        QByteArray qba = reply->readAll();
        int game_state = QString(qba).toInt();
        qDebug() << "handleGameState game state " << game_state;
        if (game_state == 2) {
            setStatusBarText("Game hosted, joining room");
            QProcess *testLaunchGameProcess  = new QProcess(backend);
            QStringList qsl = QStringList();
            qsl.append("join");
            qsl.append(backend->gid);
            testLaunchGameProcess->start("ahks/launch_dota2.exe", qsl);
            testLaunchGameProcess->waitForStarted();
            testLaunchGameProcess->waitForFinished();
            int exitCode = testLaunchGameProcess->exitCode();
            if (exitCode) {
                qDebug() << "join game failed " << exitCode;
                setStatusBarText(QString("Join game fail, room password: %1")
                                    .arg(backend->gid).toStdString().c_str());
                backend->queueState = -1;
            }
        }
    }
}

inline void handleHostRoomCreated(QNetworkReply *reply) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "handleHostRoomCreated" << status_code;
    if (status_code == 200) {
        setStatusBarText("Host game created, waiting for other players to join.");
    }

}

inline void handlePlayerScoreResponse(QNetworkReply *reply) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "handlePlayerScoreResponse" << status_code;
    if (status_code == 200) {
        QByteArray qba = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(qba);
        if (!document.isObject()) {
            qDebug() << "Invalid payload " << qba;
            return;
        }
        int score = document.object()["score"].toInt(1000);
        qDebug() << "Getting player score " << score;
        int win = document.object()["win"].toInt();
        int loss = document.object()["los"].toInt();
        setPlayerScore(score, win, loss);
    }
}

inline void handleGameJoinState(QNetworkReply *reply) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "handleGameJoinState" << status_code;
    if (status_code == 200) {
        QByteArray qba = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(qba);
        if (!document.isArray()) {
            qDebug() << "Invalid payload " << qba;
            return;
        }
        QString result = "";
        CSteamID steamID = SteamUser()->GetSteamID();
        qDebug() << "Getting steamID " << steamID.ConvertToUint64();
        for (int i = 0; i < document.array().size(); i++) {
            int state = document.array()[i].toObject()["state"].toInt(0);
            long long pid = document.array()[i].toObject()["pid"].toInteger(0);
            if (pid == steamID.ConvertToUint64()) {
                result.append(QString("我: %2\n").arg(state == 0 ? "启动中": (state == 3 ? "已放弃":"加入中")));
            } else {
                result.append(QString("玩家%1: %2\n").arg(i).arg(state == 0 ? "启动中": (state == 3 ? "已放弃":"加入中")));
            }
        }
        setGameJoinStateText(result.toStdString().c_str());
    }
}

inline void handleJoinLobby(QNetworkReply *reply) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "handleGameJoinState" << status_code;
    if (status_code == 200) {
        QByteArray qba = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(qba);
        if (!document.isObject()) {
            qDebug() << "Invalid payload " << qba;
            return;
        }

        int lid = document.object()["lbid"].toInt();
        qDebug() << "Recive lobby id " << lid;
        setStatusBarText(QString("Creating lobby %1").arg(lid).toStdString().c_str());
        // TODO update lobby UI
    }
}

extern LobbyModel *g_lobby_model;
inline void handleLobbyState(QNetworkReply *reply, int *last_invite_id, QString *lobby_id, int* queueState) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "handleGameJoinState" << status_code;
    if (status_code == 200) {
        QByteArray qba = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(qba);
        if (!document.isObject()) {
            qDebug() << "Invalid payload " << qba;
            return;
        }

        QString lid = document.object()["lbid"].toString();
        qDebug() << "Recieve lobby id " << lid;
        if (lid.length() > 0) {
            setStatusBarText(QString("Joining lobby %1").arg(lid).toStdString().c_str());
            *lobby_id = lid;
            QList<Friend> lobbyPlayers;
            QJsonArray players = document.object()["players"].toArray();
            qlonglong host_psid;
            bool all_non_host_ready = true;
            bool host_ready = false;
            for (int i = 0; i < players.size(); i++) {
                Friend f;
                qlonglong psid = players[i].toObject()["psid"].toInteger();
                f.setSid(psid);
                int host = players[i].toObject()["host"].toInt();
                f.setHost(host);
                if (host == 1) {
                    host_psid = psid;
                }
                int state = players[i].toObject()["stat"].toInt();
                f.setState(state);
                lobbyPlayers.append(f);
                if (host == 0 && state != 1) {
                    all_non_host_ready = false;
                }
                if (host == 1 && state == 1) {
                    host_ready = true;
                }
            }
            g_lobby_model->refresh(lobbyPlayers);
            qobject_cast<QQuickWindow *>(engine->rootObjects().first())
                ->findChild<QQuickItem *>("lobby_list_view")->setProperty("visible", true);
            // if i am not host, change my queue button to ready
            CSteamID steamID = SteamUser()->GetSteamID();
            if (steamID.ConvertToUint64() != host_psid) {
                showReadyButton(true);
                if (host_ready) {
                    qDebug() << "Host is queuing";
                    setStatusBarText("Host is queuing...");
                    *queueState = 1;
                }
            } else {
                disableQueueButton(all_non_host_ready);
            }
            if ((!host_ready || !all_non_host_ready) && *queueState == 1) {
                qDebug() << "Someone stopped queue.";
                setStatusBarText("Someone interrupts queue");
                *queueState = 0;
                QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
                QMetaObject::invokeMethod(window, "stopQueueFrontendOnly");
            }
        } else if (lobby_id->length() > 0) {
            qDebug() << "Quits lobby " << lobby_id;
            setStatusBarText(QString("Quiting lobby %1").arg(*lobby_id).toStdString().c_str());
            *lobby_id = "";
            showReadyButton(false);
            QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
            QQuickItem * item = window->findChild<QQuickItem *>("match_button_layout");
            item->setProperty("mode", "no_queue");
            item = window->findChild<QQuickItem *>("start_match_button");
            item->setProperty("enabled", true);
            item = window->findChild<QQuickItem *>("lobby_list_view");
            item->setProperty("visible", false);
        }
        QJsonArray invites = document.object()["invites"].toArray();
        if (invites.size() > 0) {
            QJsonObject topInvite = invites[0].toObject();
            qlonglong fsid = topInvite["fsid"].toInteger();
            int ivid = topInvite["ivid"].toInt();
            qDebug() << "Getting invite from " << fsid << " with id " << ivid;
            if (*last_invite_id != ivid) {
                qDebug() << "Displaying new invite.";
                CSteamID friendSteamID;
                friendSteamID.SetFromUint64(fsid);
                const char *friendName = SteamFriends()->GetFriendPersonaName( friendSteamID );
                QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
                QMetaObject::invokeMethod(window, "displayFriendInvite", Q_ARG(QVariant, QString(friendName)), Q_ARG(QVariant, QString("%1").arg(fsid)));
                *last_invite_id = ivid;
            }
        }
    }
}

extern GameHistoryModel *g_game_history_model;
inline void handleGameHistory(QNetworkReply *reply) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "handleGameJoinState" << status_code;
    if (status_code == 200) {
        QByteArray qba = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(qba);
        if (!document.isArray()) {
            qDebug() << "reply not array";
            return;
        }
        QJsonArray games = document.array();
        QList<GameHistory> game_histories;
        for (int i = 0; i < games.size(); i++) {
            QJsonObject game = games[i].toObject();
            int date = game["date"].toInteger();
            QString result = game["rslt"].toString();
            QJsonDocument result_json = QJsonDocument::fromJson(result.replace("'", "\"").toLatin1());
            int win_team = result_json.object()["gwin"].toInt();
            QJsonArray players = result_json.object()["play"].toArray();
            for (int j = 0; j < players.size(); j++) {
                QJsonObject player = players[j].toObject();
                qlonglong stid = player["stid"].toString().toLongLong();
                if (SteamUser()->GetSteamID().ConvertToUint64() == stid) {
                    GameHistory gh;
                    gh.hero = player["hero"].toInt();
                    gh.assist = player["asst"].toInt();
                    gh.date = date;
                    gh.death = player["deth"].toInt();
                    gh.kill = player["kill"].toInt();
                    if (player["team"].toInt() == win_team) {
                        gh.result = 0;
                    } else {
                        gh.result = 1;
                    }
                    game_histories.append(gh);
                }
            }
        }
        g_game_history_model->reset(game_histories);
    }
}

inline void handlePlayerQueueCount(QNetworkReply *reply) {
    int status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    qDebug() << "handlePlayerQueueCount" << status_code;
    if (status_code == 200) {
        QByteArray qba = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(qba);
        if (!document.isObject()) {
            qDebug() << "Invalid payload " << qba;
            return;
        }
        int qc = document.object()["qc"].toInt(0);
        qDebug() << "Getting current queue count " << qc;
        setQueueCount(qc);
    }
}

extern FriendModel *fm;
bool SteamAPIBackend::Init() {
    manager = new QNetworkAccessManager(this);
    connect(manager, &QNetworkAccessManager::finished, this, &SteamAPIBackend::NAMReplyFinished);
    manager->setTransferTimeout(10000);

    G_Steam_Backend_Initialized = SteamAPI_Init();
    if (G_Steam_Backend_Initialized) {
        fm->reset();
    }
    return G_Steam_Backend_Initialized;
}

QString SteamAPIBackend::GetPersonalName() {
    const char * personalName = SteamFriends()->GetPersonaName();
    CSteamID userSteamId =  SteamUser()->GetSteamID();
    qDebug() << "UserId is " << userSteamId.GetAccountID();
    return QString(personalName);
}

extern AvatarImageProvider *g_aip;
QString SteamAPIBackend::GetPersonalAvatar() {
    CSteamID steamID = SteamUser()->GetSteamID();
    qDebug() << "Getting steamID " << steamID.ConvertToUint64();
    int imageHandle = SteamFriends()->GetSmallFriendAvatar(steamID);
    if (imageHandle) {
        g_aip->user_avatar_image = imageHandle;
        return QString("image://avatar/user");
    }
    return QString();
}

bool SteamAPIBackend::ConnectToGameServer() {
    qDebug() << "Calling ConnectToGameServer";
    HAuthTicket authTicket = SteamUser()->GetAuthTicketForWebApi("huaijiuplatform");
    if (!authTicket) {
        qDebug() << "failed to Get auth ticket";
        return false;
    }
    return true;
}

void SteamAPIBackend::NAMReplyFinished(QNetworkReply *reply) {
    qDebug() << "NAMReplyFinished " << reply << reply->error();
    QNetworkReply::NetworkError error = reply->error();
    if (error == QNetworkReply::NetworkError::OperationCanceledError) {
        setStatusBarText("Cannot find match making server.");
        return;
    }
    QString url = reply->url().toString();
    if (url.contains("start_queue")) {
        handleStartQueueResponse(reply, &queueState, &lastPlayerQueueTime);
        return;
    }
    if (url.contains("queue_state")) {
        handleQueueStateResponse(reply, &queueState, this);
        return;
    }
    if (url.contains("dota2_launch_success")) {
        handleLaunchSuccess(reply, &gid, &is_host, this);
        return;
    }
    if (url.contains("game_state")) {
        handleGameState(reply, this);
        return;
    }
    if (url.contains("host_room_created")) {
        handleHostRoomCreated(reply);
        return;
    }
    if (url.contains("queue_player_count")) {
        handlePlayerQueueCount(reply);
        return;
    } else if (url.contains("player")) {
        handlePlayerScoreResponse(reply);
        return;
    }
    if (url.contains("game_join_stats")) {
        handleGameJoinState(reply);
        return;
    }
    if (url.contains("join_lobby")) {
        handleJoinLobby(reply);
        return;
    }
    if (url.contains("get_lobby_state")) {
        handleLobbyState(reply, &last_invite_id, &lobby_id, &queueState);
        return;
    }
    if (url.contains("game_history")) {
        handleGameHistory(reply);
        return;
    }
    if (url.contains("connect")) {
        QByteArray qba = reply->readAll();
        QJsonDocument document = QJsonDocument::fromJson(qba);
        if (document.isObject()) {
            int score = document.object()["score"].toInt(1000);
            int queue_count = document.object()["qc"].toInt(0);
            int win = document.object()["win"].toInt();
            int loss = document.object()["los"].toInt();
            enableStartQueueButton();
            setPlayerScore(score, win, loss);
            setQueueCount(queue_count);
            setStatusBarText("Connected to match making server.");
            // send request to get game history
            QString url = QString("http://%1:9581/dota683_ladder/game_history?sid=%2")
                             .arg(SERVER_IP)
                             .arg(SteamUser()->GetSteamID().ConvertToUint64());
            qDebug() << "Sending request to " << url;
            manager->get(QNetworkRequest(QUrl(url)));
        } else {
            qDebug() << QString(qba);
            setStatusBarText("Failed to match making server.");
        }
    }
}

void SteamAPIBackend::RunCallbacks() {
    SteamAPI_RunCallbacks();
    long currentTime = QDateTime::currentSecsSinceEpoch();
    if (queueState == 1 && lastPlayerQueueTime + 5 < currentTime) {
        qDebug() << "Getting player queue state";
        QString url = QString("http://%1:9581/dota683_ladder/queue_state?sid=%2")
                         .arg(SERVER_IP)
                         .arg(SteamUser()->GetSteamID().ConvertToUint64());

        qDebug() << "Sending request to: " << url;
        manager->get(QNetworkRequest(QUrl(url)));
        lastPlayerQueueTime = currentTime;
    }
    if (queueState == 3 && lastCheckGameHostedTime + 5 < currentTime) {
        qDebug() << "Getting match host state";
        QString url = QString("http://%1:9581/dota683_ladder/game_state?gid=%2").arg(SERVER_IP).arg(gid);
        qDebug() << "Sending request to: " << url;
        manager->get(QNetworkRequest(QUrl(url)));
        lastCheckGameHostedTime = currentTime;
    }
    if (queueState == 2 && launchGameProcess && lastGameProcessCheckTime + 1 < currentTime) {
        qDebug() << "Checking launch game status";
        lastGameProcessCheckTime = currentTime;
        if (launchGameProcess->state() == QProcess::NotRunning) {
            //bool shouldEnableTestButton = true;
            if (launchGameProcess->exitStatus() == QProcess::NormalExit) {
                int exitCode = launchGameProcess->exitCode();
                qDebug() << "launch Game Process exited " << exitCode;
                //if (exitCode == 1) {
                //    // Am I the host ?
                //    QString url = QString("http://%1:9581/dota683_ladder/dota2_launch_success").arg(SERVER_IP);
                //    QNetworkRequest request;
                //    request.setUrl(QUrl(url));
                //    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
                //    QJsonObject json;
                //    json.insert("token", token);
                //    qDebug() << "Sending request to " << url;
                //    setStatusBarText("Dota 2 start completes, Fetching room pw.");
                //    manager->post(request, QJsonDocument(json).toJson());
                //    queueState = 3;
                //    setStatusBarText("Launch Game success, wait for host to create game");
                //    setStartGameProgressText("启动游戏成功");
                //    RefreshGameJoinState();
                //    shouldEnableTestButton = false;
                //}
            }
            //if (shouldEnableTestButton) {
            //    qDebug() << "launch process crashed or exited with non-zero error code";
            //    // Show a popup, join game async
            //    queueState = -1;
            //    QString url = QString("http://%1:9581/dota683_ladder/abandon_game").arg(SERVER_IP);
            //    QNetworkRequest request;
            //    request.setUrl(QUrl(url));
            //    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
            //    QJsonObject json;
            //    json.insert("token", token);
            //    qDebug() << "Sending request to " << url << "fail start";
            //    manager->post(request, QJsonDocument(json).toJson());
            //    setStatusBarText("Dota 2 start failed, abandoning");

            //    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
            //    QMetaObject::invokeMethod(window, "handleLaunchFailure");
            //}
            launchGameProcess = NULL;
        }
    }
    if (queueState == 0 && launchGameProcess && lastGameProcessCheckTime + 1 < currentTime) {
        qDebug() << "Checking launch game status";
        lastGameProcessCheckTime = currentTime;
        if (launchGameProcess->state() == QProcess::NotRunning) {
            //bool shouldEnableTestButton = true;
            if (launchGameProcess->exitStatus() == QProcess::NormalExit) {
                int exitCode = launchGameProcess->exitCode();
                qDebug() << "launch Game Process exited " << exitCode;
            //    if (exitCode == 1) {
            //        QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
            //        QMetaObject::invokeMethod(window, "handleTestLaunchSuccess");
            //        testLaunchComplete = true;
            //        shouldEnableTestButton = false;
            //    }
            }
            //if (shouldEnableTestButton) {
            //    qDebug() << "launch process crashed or exited with non-zero error code";
            //    enableTestLaunchButton();
            //}
            launchGameProcess = NULL;
        }
    }
    // hosting game thread
    if (queueState == 4 && launchGameProcess && lastGameProcessCheckTime + 1 < currentTime) {
        qDebug() << "Checking host game status";
        lastGameProcessCheckTime = currentTime;
        if (launchGameProcess->state() == QProcess::NotRunning) {
            bool shouldEnableTestButton = true;
            if (launchGameProcess->exitStatus() == QProcess::NormalExit) {
                int exitCode = launchGameProcess->exitCode();
                qDebug() << "host game Process exited " << exitCode;
            //    if (exitCode == 1) {
            //        ManualHostGameSuccess();
            //        RefreshGameJoinState();
            //        shouldEnableTestButton = false;
            //    }
            }
            //if (shouldEnableTestButton) {
            //    qDebug() << "host game process crashed or exited with non-zero error code";
            //    queueState = -1;
            //    QString url = QString("http://%1:9581/dota683_ladder/abandon_game").arg(SERVER_IP);
            //    QNetworkRequest request;
            //    request.setUrl(QUrl(url));
            //    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
            //    QJsonObject json;
            //    json.insert("token", token);
            //    qDebug() << "Sending request to " << url << "fail start";
            //    manager->post(request, QJsonDocument(json).toJson());
            //    setStatusBarText("Dota 2 start failed, abandoning");
            //    gid = "";

            //    QQuickWindow *window = qobject_cast<QQuickWindow *>(engine->rootObjects().first());
            //    QMetaObject::invokeMethod(window, "handleLaunchFailure");
            //}
            launchGameProcess = NULL;
        }
    }
    if ((queueState == 0 || queueState == 1) && testLaunchComplete && lastFetchLobbyTime + 5 < currentTime && token.size() > 0) {
        lastFetchLobbyTime = currentTime;
        CSteamID userSteamId =  SteamUser()->GetSteamID();
        QString url = QString("http://%1:9581/dota683_ladder/get_lobby_state?sid=%2")
                         .arg(SERVER_IP)
                         .arg(userSteamId.ConvertToUint64());
        qDebug() << "Sending request to " << url;
        manager->get(QNetworkRequest(QUrl(url)));
    }
}
void SteamAPIBackend::OnReceiveTicketForWebApi(GetTicketForWebApiResponse_t* response) {
    qDebug() << "OnReceiveTicketForWebApi " << response->m_eResult;
    if (response->m_eResult == EResult::k_EResultOK) {
        token = QByteArray((const char *) response->m_rgubTicket, response->m_cubTicket).toHex();

        QString url = QString("http://%1:9581/dota683_ladder/connect?token=%2").arg(SERVER_IP).arg(token);
        qDebug() << "Sending request to " << url;
        manager->get(QNetworkRequest(QUrl(url)));
    } else {
        setStatusBarText("Failed to get web api token.");
    }
}

void SteamAPIBackend::OnReceiveRichPresenceJoinRequested(GameRichPresenceJoinRequested_t* response) {
    qDebug() << "OnReceiveRichPresenceJoinRequested from " << response->m_steamIDFriend.ConvertToUint64();
    QString url = QString("http://%1:9581/dota683_ladder/join_lobby").arg(SERVER_IP);
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject json;
    json.insert("token", token);
    // Inviter
    json.insert("fsid", QString("%1").arg(response->m_steamIDFriend.ConvertToUint64()));
    manager->post(request, QJsonDocument(json).toJson());

}

void SteamAPIBackend::StartMatchMaking() {
    QString url = QString("http://%1:9581/dota683_ladder/start_queue").arg(SERVER_IP);
    qDebug() << "Sending request to " << url;
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject json;
    json.insert("token", token);
    if (lobby_id.length() > 0) {
        json.insert("lid", lobby_id);
    }

    manager->post(request, QJsonDocument(json).toJson());
}

void SteamAPIBackend::CancelMatchMaking() {
    QString url = QString("http://%1:9581/dota683_ladder/stop_queue").arg(SERVER_IP);
    qDebug() << "Sending request to " << url;
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject json;
    json.insert("token", token);
    if (lobby_id.length() > 0) {
        json.insert("lid", lobby_id);
    }

    manager->post(request, QJsonDocument(json).toJson());
}

void SteamAPIBackend::CancelLaunchOrGame() {
    if (queueState == 2 || queueState == 3 || queueState == 4) {
        qDebug() << "Cancels a game launch in progress";
        queueState = 0;
        if (launchGameProcess) {
            qDebug() << "killing launch Game process";
            launchGameProcess->kill();
            launchGameProcess = NULL;
        }
        QString url = QString("http://%1:9581/dota683_ladder/abandon_game").arg(SERVER_IP);
        QNetworkRequest request;
        request.setUrl(QUrl(url));
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
        QJsonObject json;
        json.insert("token", token);
        json.insert("gid", gid);
        qDebug() << "Sending request to " << url;
        manager->post(request, QJsonDocument(json).toJson());
        gid = "";
    }
}

void SteamAPIBackend::ManualHostGameSuccess() {
    QString url = QString("http://%1:9581/dota683_ladder/host_room_created").arg(SERVER_IP);
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject json;
    json.insert("token", token);
    json.insert("gid", gid);
    qDebug() << "Sending request to " << url;
    setStatusBarText("Room created, waiting for other players to join game");
    manager->post(request, QJsonDocument(json).toJson());
}

void SteamAPIBackend::TestLaunchGame() {
    qDebug() << "testLaunchGame";
    queueState = 0;
    if (launchGameProcess) {
        launchGameProcess->kill();
    }

    launchGameProcess = new QProcess(this);
    QStringList arguments;
    arguments.append("host");
    launchGameProcess->start("ahks/launch_dota2.exe", arguments);
    launchGameProcess->waitForStarted();
}

void SteamAPIBackend::RefreshPlayerScore() {
    CSteamID userSteamId =  SteamUser()->GetSteamID();
    QString url = QString("http://%1:9581/dota683_ladder/player/%2")
                      .arg(SERVER_IP)
                      .arg(userSteamId.ConvertToUint64());
    qDebug() << "Sending request to " << url;
    manager->get(QNetworkRequest(QUrl(url)));
}

void SteamAPIBackend::RefreshQueueCount() {
    QString url = QString("http://%1:9581/dota683_ladder/queue_player_count").arg(SERVER_IP);
    qDebug() << "Sending request to " << url;
    manager->get(QNetworkRequest(QUrl(url)));
}

void SteamAPIBackend::RefreshGameJoinState() {
    if (gid.length() > 0) {
        QString url = QString("http://%1:9581/dota683_ladder/game_join_stats/%2").arg(SERVER_IP).arg(gid);
        qDebug() << "Sending request to " << url;
        manager->get(QNetworkRequest(QUrl(url)));
        return;
    }
    setGameJoinStateText("未创建");
}

void SteamAPIBackend::SendInvitation(bool invitationSent, QString sid) {
    CSteamID csid;
    CSteamID mySteamId = SteamUser()->GetSteamID();

    qDebug() << "SendInvitation called with " << invitationSent << " " << sid;
    csid.SetFromUint64(sid.toLongLong());

    if (invitationSent) {
        QString url = QString("http://%1:9581/dota683_ladder/invite_to_lobby").arg(SERVER_IP);
        qDebug() << "Sending request to " << url;
        QNetworkRequest request;
        request.setUrl(QUrl(url));
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
        QJsonObject json;
        json.insert("token", token);
        json.insert("fsid", QString("%1").arg(sid));
        manager->post(request, QJsonDocument(json).toJson());

        bool success = SteamFriends()->InviteUserToGame(csid, QString("joinparty_%1").arg(mySteamId.ConvertToUint64()).toStdString().c_str());
        qDebug() << "invitation sent " << success;
    }
}

void SteamAPIBackend::RefreshGameHistory() {
    QString url = QString("http://%1:9581/dota683_ladder/game_history?sid=%2")
                      .arg(SERVER_IP)
                     .arg(SteamUser()->GetSteamID().ConvertToUint64());
    qDebug() << "Sending request to " << url;
    manager->get(QNetworkRequest(QUrl(url)));
}

void SteamAPIBackend::SetTestLaunchComplete() {
    qDebug() << "SetTestlaunchComplete called";
    this->testLaunchComplete = true;
}

void SteamAPIBackend::AcceptInvite(QString qsid) {
    qDebug() << "AcceptInvite " << qsid;
    QString url = QString("http://%1:9581/dota683_ladder/join_lobby").arg(SERVER_IP);
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject json;
    json.insert("token", token);
    // Inviter
    json.insert("fsid", qsid);
    manager->post(request, QJsonDocument(json).toJson());
}

void SteamAPIBackend::DeclineInvite(QString qsid) {

    qDebug() << "DeclineInvite " << qsid;
    QString url = QString("http://%1:9581/dota683_ladder/join_lobby").arg(SERVER_IP);
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject json;
    json.insert("token", token);
    // Inviter
    json.insert("fsid", qsid);
    json.insert("decline", 1);
    manager->post(request, QJsonDocument(json).toJson());
}

void SteamAPIBackend::LeaveLobby() {
    qDebug() << "Leaving Lobby " << lobby_id;
    if (lobby_id.isEmpty()) {
        return;
    }
    QString url = QString("http://%1:9581/dota683_ladder/quit_lobby").arg(SERVER_IP);
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject json;
    json.insert("token", token);
    json.insert("lid", lobby_id);
    manager->post(request, QJsonDocument(json).toJson());

    lobby_id.clear();

    QList<Friend> lobbyPlayers;
    g_lobby_model->refresh(lobbyPlayers);
    showReadyButton(false);
}

void SteamAPIBackend::LobbyKickPlayer(QString sid) {
    qDebug() << "Kicking lobby " << lobby_id << " player " << sid;
    QString url = QString("http://%1:9581/dota683_ladder/lobby_kick_player").arg(SERVER_IP);
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QJsonObject json;
    json.insert("token", token);
    json.insert("lid", lobby_id);
    json.insert("psid", sid.toLongLong());
    manager->post(request, QJsonDocument(json).toJson());

    g_lobby_model->kick_player(sid);
}

void SteamAPIBackend::SetLobbyReady(bool ready) {
    if (ready) {
        QString url = QString("http://%1:9581/dota683_ladder/lobby_player_ready").arg(SERVER_IP);
        qDebug() << "Sending request to " << url;
        QNetworkRequest request;
        request.setUrl(QUrl(url));
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
        QJsonObject json;
        json.insert("token", token);
        json.insert("lid", this->lobby_id);

        manager->post(request, QJsonDocument(json).toJson());
    } else {
        QString url = QString("http://%1:9581/dota683_ladder/stop_queue").arg(SERVER_IP);
        qDebug() << "Sending request to " << url;
        QNetworkRequest request;
        request.setUrl(QUrl(url));
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
        QJsonObject json;
        json.insert("token", token);
        json.insert("lid", this->lobby_id);

        manager->post(request, QJsonDocument(json).toJson());
    }
}
